package org.googlecode.viewt.core.tools.web;

import org.apache.velocity.VelocityContext;
import org.googlecode.viewt.core.tools.AbstractVelocityGenerator;
import org.googlecode.viewt.core.tools.LogicDescRepository;
import org.googlecode.viewt.core.tools.formbean.FormBeanCfgRepository;
import org.googlecode.viewt.core.tools.web.types.Action;
import org.googlecode.viewt.core.tools.web.types.Actions;

public abstract class BaseWebGenerator extends AbstractVelocityGenerator {
	public static final String CONTEXT_PROP_ACTIONS = "ACTIONS";
	public static final String CONTEXT_PROP_UTIL = "UTILITY";
	public static final String CONTEXT_PROP_GENERATOR = "GENERATOR";
	public static final String CONTEXT_PROP_PREFIX = "PREFIX";
	public static final String CONTEXT_PROP_PRJNAME = "PROJECT";
	public static final String CONTEXT_PROP_MODNAME = "MODULE";
	public static final String CONTEXT_PROP_CURACTIONDEF = "CURRENTACTION";
	public static final String CONTEXT_PROP_LOGICREPOSITORY = "REPOSITORY";
	public static final String CONTEXT_PROP_FORMBEANREPOSITORY = "FORMBEANREPOSITORY";
	private Actions actionsDef;
	private FormBeanCfgRepository formbeanRepository;
	private String prePackName;
	private String[] blPaths;
	private String destPath;
	private String fileTemplatePath;

	public BaseWebGenerator() {
		this.actionsDef = null;

		this.formbeanRepository = null;

		this.prePackName = null;

		this.blPaths = null;

		this.destPath = null;

		this.fileTemplatePath = null;
	}

	public void init(Actions actionsDef, String destPath) throws Exception {
		super.init();
		setActionsDef(actionsDef);
		setDestPath(destPath);
	}

	public void performGen() throws Exception {
		if ((this.actionsDef == null) || (this.destPath == null)) {
			getLogger()
					.error(
							"Perform generation fail, set config and destination first");
			throw new Exception("config or enviroment not set");
		}

		VelocityContext context = getContext();
		if (null == context) {
			context = new VelocityContext();
			setContext(context);
		}
		context.put("ACTIONS", this.actionsDef);
		context.put("FORMBEANREPOSITORY", this.formbeanRepository);
		context.put("UTILITY", new WebActionUtil());
		context.put("GENERATOR", this);
		context.put("PREFIX", this.prePackName);
		context.put("PROJECT", this.actionsDef.getProjectName());
		context.put("MODULE", this.actionsDef.getModuleName());

		setupContext();

		Action[] actions = this.actionsDef.getAction();
		for (int i = 0; i < actions.length; ++i) {
			Action actionDef = actions[i];
			String actionName = actionDef.getName();

			if (needGenerate(actionName)) {
				getLogger().debug(
						"Begin generate web action:" + actionName
								+ ", bl interface:"
								+ actionDef.getBlInterface()
								+ ", bl implement:"
								+ actionDef.getBlImplement() + ", method:"
								+ actionDef.getBusinessMethod());

				if (actionDef.getFormBeanDef() != null) {
					String formbeanClass = actionDef.getFormBeanDef()
							.getClassName();
					if (this.formbeanRepository == null) {
						getLogger()
								.error(
										"Dependent formbean config not set, can not verify formbean class");
						throw new Exception(
								"Dependent formbean config not set, can not verify formbean class");
					}

					if (this.formbeanRepository
							.getFormBeanConfig(formbeanClass) == null) {
						getLogger().error(
								"Can not find formbean class:" + formbeanClass
										+ " definition");
						throw new Exception("Can not find formbean class:"
								+ formbeanClass + " definition");
					}

				}

				String blintFile = WebActionUtil.findSource(this.blPaths,
						actionDef.getBlInterface());
				if (blintFile == null) {
					getLogger().error(
							"Can not find business interface:"
									+ actionDef.getBlInterface());
					throw new Exception("Can not find business interface:"
							+ actionDef.getBlInterface());
				}
				String blimpFile = WebActionUtil.findSource(this.blPaths,
						actionDef.getBlImplement());
				if (blimpFile == null) {
					getLogger().error(
							"Can not find business implement:"
									+ actionDef.getBlImplement());
					throw new Exception("Can not find business implement:"
							+ actionDef.getBlImplement());
				}

				LogicDescRepository logicRepository = new LogicDescRepository();
				logicRepository.setBLFile(blintFile, blimpFile);

				if (logicRepository.getBLInterface().getMethod(
						actionDef.getBusinessMethod()) == null) {
					getLogger()
							.error(
									"Specified method:"
											+ actionDef.getBusinessMethod()
											+ " of action:" + actionName
											+ " not found");
					throw new Exception("Specified method:"
							+ actionDef.getBusinessMethod() + " of action:"
							+ actionName + " not found");
				}

				context.put("REPOSITORY", logicRepository);

				String templateName = getTemplate(actionName);
				String outputFile = getOutputFile(actionName);
				if ((null == templateName) || ("".equals(templateName))) {
					getLogger().error(
							"Empty template name:" + templateName
									+ ", generation fail");
					throw new Exception("Can not get template for web action:"
							+ actionName);
				}
				if ((null == outputFile) || ("".equals(outputFile))) {
					getLogger().error(
							"Empty output file:" + outputFile
									+ ", generation fail");
					throw new Exception(
							"Can not get output file for web action:"
									+ actionName);
				}
				context.put("CURRENTACTION", actionDef);

				setupContext(actionName);

				singleOutput(templateName, outputFile);

				cleanContext(actionName);

				context.remove("CURRENTACTION");
				context.remove("REPOSITORY");

				getLogger().debug(
						"Generate web action:" + actionName + " succeed");
			} else {
				getLogger().debug(
						"Need not generate web action:" + actionName
								+ ", bypass");
			}

		}

		cleanContext();

		context.remove("MODULE");
		context.remove("PROJECT");
		context.remove("PREFIX");
		context.remove("GENERATOR");
		context.remove("UTILITY");
		context.remove("FORMBEANREPOSITORY");
		context.remove("ACTIONS");

		getLogger().debug("Perform code generation done.");
	}

	public void setActionsDef(Actions actionsDef) {
		this.actionsDef = actionsDef;
	}

	public Actions getActionsDef() {
		return this.actionsDef;
	}

	public void setFormbeanRepository(FormBeanCfgRepository formbeanRepository) {
		this.formbeanRepository = formbeanRepository;
	}

	public FormBeanCfgRepository getFormbeanRepository() {
		return this.formbeanRepository;
	}

	public void setBLPath(String[] blPaths) {
		this.blPaths = blPaths;
	}

	public String[] getBLPath() {
		return this.blPaths;
	}

	public void setPrePackName(String prePackName) {
		this.prePackName = prePackName;
	}

	public String getPrePackName() {
		return this.prePackName;
	}

	public void setDestPath(String destPath) {
		this.destPath = destPath;
	}

	public String getDestPath() {
		return this.destPath;
	}

	public void setFileTemplatePath(String fileTemplatePath) {
		this.fileTemplatePath = fileTemplatePath;
	}

	public String getFileTemplatePath() {
		return this.fileTemplatePath;
	}

	public String getPackageTemplatePath() {
		return "resources/templates/web";
	}

	public abstract String getTemplate(String paramString) throws Exception;

	public abstract String getOutputFile(String paramString) throws Exception;

	public abstract boolean needGenerate(String paramString) throws Exception;

	public abstract void setupContext() throws Exception;

	public abstract void setupContext(String paramString) throws Exception;

	public abstract void cleanContext(String paramString) throws Exception;

	public abstract void cleanContext() throws Exception;
}